//
//  ZYHttpClient.swift
//  SwiftDemo1
//
//  Created by wzp on 2025/6/8.
//

import Foundation
import Alamofire
enum ZYHttpError: Error {
    case invalidURL
    case noData
    case decodingError
    case serverError(Int)
    case networkError(Error)
    case cancelled
    case timeout
    
    var localDesc: String {
        switch self {
        case .invalidURL:
            return "无效的URL"
        case .noData:
            return "没有数据"
        case .decodingError:
            return "数据解析失败"
        case .serverError(let code):
            return "服务器错误： \(code)"
        case .networkError(let error):
            return "网络错误： \(error.localizedDescription)"
        case .cancelled:
            return "请求已取消"
        case .timeout:
            return "请求超时"
        }
    }
}

enum ZYHttpResult<T> {
    case success(T)
    case failure(ZYHttpError)
}

class ZYHttpClient {
    static let shareInstance: ZYHttpClient = ZYHttpClient()
    private let session: Session
//    private let baseUrl: String
    
    private init() {
        let configuration = URLSessionConfiguration.default
        configuration.timeoutIntervalForRequest = 30
        configuration.timeoutIntervalForResource = 60
        session = Session(configuration: configuration)
//        self.baseUrl = ""
    }
    
    // MARK: - 通用请求方法
    func request<T: Codable>(_ urlStr: String,
                             method: HTTPMethod = .get,
                             parameters: Parameters? = nil,
                             encoding: ParameterEncoding = URLEncoding.default,
                             headers: HTTPHeaders? = nil,
                             responseType: T.Type,
                             completion: @escaping @Sendable (ZYHttpResult<T>) ->Void) {
        session.request(urlStr,
                        method: method,
                        parameters: parameters,
                        headers: headers).validate().responseDecodable(of: T.self) { response in
            self.handleResponse(response, completion: completion)
        }
    }
    
    func get<T: Codable>(_ urlStr: String,
                         method: HTTPMethod = .get,
                         parameters: Parameters? = nil,
                         encoding: ParameterEncoding = URLEncoding.default,
                         header: HTTPHeaders? = nil,
                         responseType: T.Type,
                         completion: @escaping @Sendable (ZYHttpResult<T>)->Void)
    {
        request(urlStr,
                method: method,
                parameters: parameters,
                encoding: encoding,
                headers: header,
                responseType: responseType,
                completion: completion)
    }
    
    func post<T: Codable>(_ urlStr: String,
                              parameters: Parameters? = nil,
                              headers: HTTPHeaders? = nil,
                              responseType: T.Type,
                              completion: @escaping @Sendable (ZYHttpResult<T>) -> Void) {
        request(urlStr,
                method: .post,
                parameters: parameters,
                encoding: JSONEncoding.default,
                headers: headers,
                responseType: responseType,
                completion: completion)
    }
    
    
    
    private func handleResponse<T: Codable>(_ response: DataResponse<T, AFError>, completion:@escaping @Sendable (ZYHttpResult<T>)->Void) {
        switch response.result {
            case .success(let value):
                completion(.success(value))
            case .failure(let error):
                completion(.failure(mapAFError(error)))
        }
    }
    
    private func mapAFError(_ error: AFError) -> ZYHttpError {
            switch error {
            case .invalidURL(_):
                return .invalidURL
            case .responseValidationFailed(reason: .unacceptableStatusCode(code: let code)):
                return .serverError(code)
            case .responseSerializationFailed(_):
                return .decodingError
            case .sessionTaskFailed(let sessionError):
                if let urlError = sessionError as? URLError {
                    switch urlError.code {
                    case .cancelled:
                        return .cancelled
                    case .timedOut:
                        return .timeout
                    default:
                        return .networkError(urlError)
                    }
                }
                return .networkError(sessionError)
            default:
                return .networkError(error)
            }
        }
}


extension ZYHttpClient {
    func getDictionary(_ urlStr: String,
                       parameters: Parameters? = nil,
                       headers: HTTPHeaders? = nil,
                       completion: @escaping @Sendable (ZYHttpResult<[String: Any]>) -> Void) {
        self.requestDictionary(urlStr, method: .get, parameters: parameters, headers: headers, completion: completion)
    }
    
    func postDictionary(_ urlStr: String,
                       parameters: Parameters? = nil,
                       headers: HTTPHeaders? = nil,
                       completion: @escaping @Sendable (ZYHttpResult<[String: Any]>) -> Void) {
        self.requestDictionary(urlStr, method: .post, parameters: parameters, headers: headers, completion: completion)
    }
    
    func requestDictionary(_ urlStr: String,
                           method: HTTPMethod = .get,
                           parameters: Parameters? = nil,
                           encoding: ParameterEncoding = URLEncoding.default,
                           headers: HTTPHeaders? = nil,
                           completion: @escaping @Sendable (ZYHttpResult<[String: Any]>) -> Void) {
        session.request(urlStr,
                        method: method,
                        parameters: parameters,
                        encoding: encoding,
                        headers: headers).validate().response { response in
            self.handleResponseData(response: response, completion: completion)
        }
    }
    
    private func handleResponseData(response: DataResponse<Data?, AFError>,
                                    completion: @escaping @Sendable (ZYHttpResult<[String: Any]>) -> Void) {
        switch response.result {
        case .success(let data):
            guard let data = data else {
                completion(.failure(.noData))
                return
            }
            do {
                if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
                    completion(.success(json))
                }
                else {
                    completion(.failure(.decodingError))
                }
            } catch {
                completion(.failure(.decodingError))
            }
        case .failure(let error):
            completion(.failure(mapAFError(error)))
        }
    }
}
